package com.qunar.wan.web.controller;

import com.google.common.base.Function;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.qunar.wan.common_api.model.*;
import com.qunar.wan.common_api.model.enums.ActivityState;
import com.qunar.wan.common_api.model.enums.EvaluateStatus;
import com.qunar.wan.common_api.model.enums.Role;
import com.qunar.wan.common_api.service.*;
import com.qunar.wan.util.DateUtil;
import com.qunar.wan.util.HTMLTagsUtil;
import com.qunar.wan.util.HttpServletUtil;
import com.qunar.wan.web.controller.common.AbstractController;
import com.qunar.wan.web.filter.AuthenticationController;
import org.apache.commons.lang3.StringUtils;
import com.qunar.wan.common_api.serializer.RowBounds;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.http.HttpServletRequest;
import java.net.URLDecoder;
import java.sql.Timestamp;
import java.text.ParseException;
import java.util.*;

import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;

/**
 * User: cyoung Date: 11/27/13 Time: 3:28 PM
 */
@Controller
@RequestMapping("/activity")
public class ActivityController extends AbstractController implements AuthenticationController {
    private Logger logger = LoggerFactory.getLogger(ActivityController.class);

    @Resource
    private ActivityService activityService;
    @Resource
    private UserActivityService userActivityService;
    @Resource
    private LuceneSearchService luceneSearchService;
    @Resource
    private UserService userService;
    @Resource
    private UserClassifyService userClassifyService;
    @Resource
    private CacheService cacheService;

    private static final String DEFAULT_POSTER = "12345.jpg";
    /**
     * 白名单请求链接
     */

    private List<String> whiteUrls = new ArrayList<String>(8) {
        {
            add("/activity/hots.do");
            add("/activity/classfiyHots.do");
            add("/activity/subclassifyHots.do");
            add("/activity/detail.do");
            add("/activity/classify.do");
            add("/activity/search.do");
            add("/activity/dayActivities.do");
            add("/activity/published.do");
        }
    };

    /**
     * 所有活动中热门活动
     */
    @RequestMapping("/hots")
    @ResponseBody
    public Object hotActivities(@RequestParam(value = "pageNum") int pageNum, @RequestParam(defaultValue = "3") int num) {
        checkArgument(pageNum > 0, "pageNum必须大于0");
        long start = System.currentTimeMillis();
        List<Activity> activities = activityService.selectHots(new RowBounds((pageNum - 1) * num, pageNum * num));
        return dataJson(activities, System.currentTimeMillis() - start);
    }

    /**
     * 大类下热门活动，一次性返回所有大类的热门活动
     */
    @RequestMapping("/classfiyHots")
    @ResponseBody
    public Object hotClaActivities(@RequestParam(defaultValue = "4") int num,
                                   @RequestParam(defaultValue = "0", required = false) int claId) {
        long start = System.currentTimeMillis();
        List<Map> results = new ArrayList<Map>();
        if (claId > 0) {
            List<Activity> activities = activityService.selectByClassify(claId, 0, false, new RowBounds(0, num));
            return dataJson(activities, System.currentTimeMillis() - start);
        }
        List<Classify> classifies = cacheService.readClasCache();
        for (Classify classify : classifies) {
            Map<String, Object> map = new LinkedHashMap<String, Object>();
            map.put("id", classify.getId());
            map.put("name", classify.getClaName());
            List<Activity> activities = activityService.selectByClassify(classify.getId(), 0, false, new RowBounds(0,
                    num));
            map.put("activities", activities);
            results.add(map);
        }
        return dataJson(results, System.currentTimeMillis() - start);
    }

    /**
     * 小类下热门活动
     */
    @RequestMapping("/subclassifyHots")
    @ResponseBody
    public Object subHotActivities(@RequestParam int subClaId,
                                   @RequestParam(defaultValue = "3", required = false) int num) {
        long start = System.currentTimeMillis();
        List<Activity> activities = activityService.selectByClassify(0, subClaId, false, new RowBounds(0, num));
        return dataJson(activities, System.currentTimeMillis() - start);
    }

    /**
     * （大，小）分类下的活动
     */
    @RequestMapping("/classify")
    @ResponseBody
    public Object classifyActivities(@RequestParam(defaultValue = "0", required = false, value = "id") int claId,
                                     @RequestParam(defaultValue = "0", required = false, value = "sid") int subClaId,
                                     @RequestParam(defaultValue = "1", required = false) int page,
                                     @RequestParam(defaultValue = "10", required = false) int pageSize,
                                     @RequestParam(required = false) String dayStr) {
        long start = System.currentTimeMillis();
        checkArgument(page > 0 && pageSize > 0, "page and pageSize must greater than 0");
        int recodeNum = 0;
        List<Activity> activities = new ArrayList<Activity>(pageSize);
        RowBounds rowBounds = new RowBounds((page - 1) * pageSize, pageSize);
        /** 最近一周 */
        if (!StringUtils.isEmpty(dayStr)) {
            String[] days = dayStr.trim().split(",");
            activities = activityService.selectByDays(claId, subClaId, days, rowBounds);
            recodeNum = activityService.selectCountByDays(claId, subClaId, days);
        } else {
            /*** 大小，分类 */
            activities = activityService.selectByClassify(claId, subClaId, true, rowBounds);
            recodeNum = activityService.selectCountByClassify(claId, subClaId, true);
        }
        int totalPage = (recodeNum - 1) / pageSize + 1;
        List<ActivityIndex> activityIndexes = convert2Index(activities);
        return dataJson(activityIndexes, System.currentTimeMillis() - start).put("totalPage", totalPage);
    }

    private List<ActivityIndex> convert2Index(List<Activity> activities) {
        return Lists.transform(activities, new Function<Activity, ActivityIndex>() {
            @Override
            public ActivityIndex apply(Activity activity) {
                ActivityIndex activityIndex = new ActivityIndex();
                activityIndex.setId(activity.getId());
                activityIndex.setTitle(activity.getTitle());
                activityIndex.setSummary(StringUtils.substring(HTMLTagsUtil.delHTMLTag(activity.getDescription()), 0,
                        200) + "...");
                activityIndex.setAvgFee(activity.getAvgFee());
                activityIndex.setPeopleNum(activity.getPeopleNum());
                activityIndex.setPlace(activity.getPlace());
                activityIndex.setSponsor(checkNotNull(userService.selectUserById(activity.getUserId())).getUserName());
                activityIndex.setStartDay(activity.getStartDay());
                activityIndex.setStartHHMM(activity.getStartHHMM());
                activityIndex.setPoster(activity.getPoster());
                return activityIndex;
            }
        });
    }

    @RequestMapping("/detail")
    @ResponseBody
    public Object activityDetail(@RequestParam int id, HttpServletRequest request) {
        long start = System.currentTimeMillis();
        String visitorIdStr = userService.currentLogonUser()==null?"":userService.currentLogonUser().getId()+"";
        Activity activity = checkNotNull(activityService.selectById(id));
        /** 未登录户只能查看审核通过活动的detail */
        if (StringUtils.isEmpty(visitorIdStr)) {
            if (activity.getState() == ActivityState.CHECK_SUCCESS) {
                return dataJson(activity, System.currentTimeMillis() - start);
            }
            return errorJson(HttpStatus.FORBIDDEN, "该活动审核未通过", System.currentTimeMillis() - start);
        }
        User viewer = userService.selectUserById(Integer.parseInt(visitorIdStr));
        /** 登录用户非管理员只能查看审核通过活动Detail */
        if (viewer.getRole() == Role.USER && activity.getState() != ActivityState.CHECK_SUCCESS) {
            return errorJson(HttpStatus.FORBIDDEN, "该活动审核未通过", System.currentTimeMillis() - start);
        }
        /** 登录用户是否已经报名参加活动 */
        UserActivity userActivity = userActivityService.selectByUserIdActId(viewer.getId(), activity.getId());
        if (userActivity != null) {
            return dataJson(activity, System.currentTimeMillis() - start).put("evaluateStatus",
                    userActivity.getEvaluateStatus().getCode());
        }
        return dataJson(activity, System.currentTimeMillis() - start);
    }

    @RequestMapping(value = "/add", method = RequestMethod.POST)
    @ResponseBody
    public Object addActivity(@RequestBody Activity activity, HttpServletRequest request) throws Exception {
        long start = System.currentTimeMillis();
        int userId = checkNotNull(userService.currentLogonUser()).getId();
        activity = fillAndCheckFields(activity, checkNotNull(userService.selectUserById(userId)));
        if (activity.getStartTime().before(new Date()) || activity.getStartTime().after(activity.getEndTime())) {
            logger.warn("开始日期不能晚于当前时间和结束日期:\"{}\"", activity.getTitle());
            return errorJson(HttpStatus.BAD_REQUEST, "开始日期不能晚于当前时间和结束日期", System.currentTimeMillis() - start);
        }
        activityService.insertObj(activity);
        return dataJson("发布活动成功", System.currentTimeMillis() - start);
    }

    private Activity fillAndCheckFields(Activity activity, User user) throws ParseException {

        activity.setUserId(user.getId());
        activity.setStartTime(DateUtil.combine2Date(activity.getStartDay(), activity.getStartHHMM()));
        activity.setEndTime(DateUtil.combine2Date(activity.getEndDay(), activity.getEndHHMM()));
        activity.setCreateTime(new Timestamp(System.currentTimeMillis()));
        activity.setDeadline(activity.getStartTime());
        activity.setState(ActivityState.CHECKING);
        if (StringUtils.isEmpty(activity.getPoster())) {
            activity.setPoster(DEFAULT_POSTER);
        }
        return activity;

    }

    @RequestMapping(value = "/signUp")
    @ResponseBody
    public Object signUp(@RequestParam int activityId, HttpServletRequest request) {
        long start = System.currentTimeMillis();
        String username = checkNotNull(userService.currentLogonUser()).getUserName();
        boolean flag = userActivityService.signUp(activityId, checkNotNull(userService.selectUserByName(username))
                .getId());
        return dataJson(flag ? "报名成功" : "报名失败", System.currentTimeMillis() - start);
    }

    @RequestMapping(value = "/published")
    @ResponseBody
    public Object publishedActivities(@RequestParam(value = "id") int userId, @RequestParam int page,
                                      @RequestParam(defaultValue = "4", value = "perPageNum") int pageSize) {
        Preconditions.checkNotNull(userId);
        checkArgument(page > 0, "page must greater than 0");
        long start = System.currentTimeMillis();
        RowBounds rowBounds = new RowBounds((page - 1) * pageSize, pageSize);
        return dataJson(activityService.selectPublished(userId, rowBounds), System.currentTimeMillis() - start).put(
                "pageNum", (activityService.selectPublishedCount(userId) - 1) / pageSize + 1);
    }

    @RequestMapping(value = "/notExamine/count")
    @ResponseBody
    public Object notExamineCount() {
        long start = System.currentTimeMillis();
        return dataJson(activityService.selectNotExaminedCount(), System.currentTimeMillis() - start);
    }

    @RequestMapping(value = "/assess")
    @ResponseBody
    public Object assessActivity(@RequestParam int actId, @RequestParam int state, HttpServletRequest request) {
        long start = System.currentTimeMillis();
        User user = userService.currentLogonUser();
        Activity activity = checkNotNull(activityService.selectById(actId));
        String result = userActivityService.assess(activity, EvaluateStatus.codeOf(state), user);
        return dataJson(result, System.currentTimeMillis() - start);
    }

    @RequestMapping(value = "/search")
    @ResponseBody
    public Object search(@RequestParam String keywords,
                         @RequestParam(defaultValue = "10", required = false) int pageSize,
                         @RequestParam(defaultValue = "1") int page, HttpServletRequest request) throws Exception {
        long start = System.currentTimeMillis();
        keywords = URLDecoder.decode(keywords, "UTF-8");
        /** 记录用户搜索信息，便于以后推送（虽然不在此次需求） */
        String username =userService.currentLogonUser() == null ? null:userService.currentLogonUser().getUserName();
        String userinfo = null == username ? HttpServletUtil.getClientIp(request) : username;
        logger.info("用户{}搜索\"{}\",第{}页", userinfo, keywords, page);
        SearchResult result = luceneSearchService.search(keywords, pageSize, page);
        if (result == null) {
            List<Activity> recommend = new ArrayList<Activity>(5);
            if (StringUtils.isEmpty(username)) {
                return dataJson("暂未找到符合条件的数据", System.currentTimeMillis() - start).put("recommend", Arrays.asList());
            }
            /** 搜索结果为空时，根据用户关注推荐部分活动，数量为5 */
            List<SubClassify> userSubclassifies = userClassifyService.selectByuserId(userService.selectUserByName(
                    username).getId());
            if (userSubclassifies.isEmpty()) {
                return dataJson("暂未找到符合条件的数据", System.currentTimeMillis() - start);
            }
            for (SubClassify subClassify : userSubclassifies) {
                if (recommend.size() >= 5) {
                    break;
                }
                recommend.addAll(activityService.selectByClassify(0, subClassify.getId(), false, new RowBounds(0, 1)));
            }
            return dataJson("", System.currentTimeMillis() - start).put("recommend", convert2Index(recommend));
        }
        return dataJson(result.getIndexLists(), System.currentTimeMillis() - start).put("totalPage",
                result.getTotalPage()).put("recommend", Arrays.asList());

    }

    @Override
    public boolean isAuthenticated(String pathInfo, ServletRequest req) {
        HttpServletRequest request = (HttpServletRequest) req;
        User user = userService.currentLogonUser();
        if (pathInfo.contains("/notExamine/count")) {
            return (user.getRole() == Role.MANAGER || user.getRole() == Role.SUPERMANAGER);
        }
        return true;
    }

    @Override
    public boolean isCheckRequired(ServletRequest req) {
        return !whiteUrls.contains(HttpServletUtil.getPathInfo(req));
    }

    /**
     * *
     * bean初始化时建立索引文件 TODO 不合理，主要问题是打开上次索引文件时没有结果
     *
     * @throws java.io.IOException
     */
//    @PostConstruct
//    public void reIndex() throws IOException {
//        long start = System.currentTimeMillis();
//        DocumentWriter.addIndexDocs(activityConvertService,
//                activityService.selectByQuery(new Query("state", ActivityState.CHECK_SUCCESS)));
//        LuceneContext.getIndexWriter().forceMerge(3);
//        LuceneContext.getIndexWriter().commit();
//        logger.info("第一次重建索引耗时{}ms", System.currentTimeMillis() - start);
//    }
}
